using System;
using System.IO;
using FireStarter.CodeGeneration;
using FireStarterModeller.BO;
using FireStarterModeller.Test.BO;
using NUnit.Framework;

namespace FireStarter.Test.CodeGeneration
{
    [TestFixture]
    public abstract class TestProjectGeneratorBase : TestGeneratorBase
    {

        protected abstract IProjectGenerator CreateProjectGenerator();
        protected abstract IProjectGenerator CreateProjectReadyToGenerate();

        protected static void CreateSolutionGenerator(IProjectGenerator projectGenerator)
        {
            DMSolution dmSolution = TestUtilsDMSolution.CreateUnsavedValidDMSolution();
            dmSolution.GenerationSettings = new GenerationSettings();
            ISolutionGenerator solutionGenerator = new SolutionGenerator();
            solutionGenerator.HabaneroReferencePath = GetRootedPath(Path.Combine(TEST_PROJECTS_FOLDER, GetRandomString()));
            projectGenerator.SolutionGenerator = solutionGenerator;
            projectGenerator.SolutionGenerator.SolutionDirectory = GetRootedPath(TEST_PROJECTS_FOLDER);
            projectGenerator.SolutionGenerator.ModelSolution = dmSolution;
            projectGenerator.SolutionGenerator.ModelSolution.ApplicationName = TestUtilsCodeGen.GetRandomString();
        }

        #region Utility Methods

        protected static void AssertHasReference(string projectFileContents, string assemblyFileName)
        {
            string assemblyName = Path.GetFileNameWithoutExtension(assemblyFileName);
            StringAssert.Contains(string.Format(@"<Reference Include=""{0}"">", assemblyName), projectFileContents);
            StringAssert.Contains(string.Format(@"<HintPath>{0}</HintPath>", assemblyFileName), projectFileContents);
            StringAssert.Contains(@"</Reference>", projectFileContents);
        }

        protected static void AssertHasNotReference(string projectFileContents, string assemblyFileName)
        {
            string assemblyName = Path.GetFileNameWithoutExtension(assemblyFileName);
            Assert.IsFalse(projectFileContents.Contains(string.Format(@"<Reference Include=""{0}"">", assemblyName)));
            Assert.IsFalse(projectFileContents.Contains(string.Format(@"<HintPath>{0}</HintPath>", assemblyFileName)));
        }

        protected static void AssertHasProjectReference(string projectFileContents, IProjectGenerator projectGenerator, ProjectFileManager referencedProjectFileManager)
        {
            string relativeProjectPath = Utilities.GetRelativePath(referencedProjectFileManager.ProjectFileName, projectGenerator.ProjectPath);
            string projectGuidString = referencedProjectFileManager.ProjectGuid.ToString("B").ToUpper();
            StringAssert.Contains(string.Format(@"<ProjectReference Include=""{0}"">", relativeProjectPath), projectFileContents);
            StringAssert.Contains(string.Format(@"<Project>{0}</Project>", projectGuidString), projectFileContents);
            StringAssert.Contains(string.Format(@"<Name>{0}</Name>", referencedProjectFileManager.AssemblyName), projectFileContents);
            StringAssert.Contains(@"</ProjectReference>", projectFileContents);
        }

        protected static void AssertHasSystemReference(string projectFileContents, string assemblyName)
        {
            StringAssert.Contains(string.Format(@"<Reference Include=""{0}"" />", assemblyName), projectFileContents);
        }

        #endregion Utility Methods

        [Test]
        public void TestProjectName()
        {
            //---------------Set up test pack-------------------
            string projectName = GetRandomString();
            IProjectGenerator projectGenerator = CreateProjectGenerator();
            //---------------Assert Precondition----------------
            Assert.IsNull(projectGenerator.ProjectName);
            //---------------Execute Test ----------------------
            projectGenerator.ProjectName = projectName;
            //---------------Test Result -----------------------
            Assert.AreEqual(projectName, projectGenerator.ProjectName);
        }

        [Test]
        public void TestGenerate_Fails_SolutionGeneratorNotSet()
        {
            //---------------Set up test pack-------------------
            IProjectGenerator projectGenerator = CreateProjectReadyToGenerate();
            projectGenerator.SolutionGenerator = null;
            //---------------Assert Precondition----------------
            Assert.IsNull(projectGenerator.SolutionGenerator);
            //---------------Execute Test ----------------------
            try
            {
                projectGenerator.Generate();
                //---------------Test Result -----------------------
                Assert.Fail("Expected to throw an PropertyMissingException");
            } 
            catch (PropertyMissingException ex)
            {
                Assert.AreEqual("SolutionGenerator", ex.PropertyName);
            }
        }

        [Test]
        public void TestGenerate_Fails_ProjectNameNotSet()
        {
            //---------------Set up test pack-------------------
            IProjectGenerator projectGenerator = CreateProjectReadyToGenerate();
            projectGenerator.ProjectName = null;
            //---------------Assert Precondition----------------
            Assert.IsNull(projectGenerator.ProjectName);
            //---------------Execute Test ----------------------
            try
            {
                projectGenerator.Generate();
                //---------------Test Result -----------------------
                Assert.Fail("Expected to throw an PropertyMissingException");
            }
            catch (PropertyMissingException ex)
            {
                Assert.AreEqual("ProjectName", ex.PropertyName);
            }
        }

        [Test]
        public void TestGenerate_Fails_ProjectPathNotSet()
        {
            //---------------Set up test pack-------------------
            IProjectGenerator uiProjectGenerator = CreateProjectReadyToGenerate();
            uiProjectGenerator.ProjectPath = null;
            //---------------Assert Precondition----------------
            Assert.IsNull(uiProjectGenerator.ProjectPath);
            //---------------Execute Test ----------------------
            try
            {
                uiProjectGenerator.Generate();
                //---------------Test Result -----------------------
                Assert.Fail("Expected to throw an PropertyMissingException");
            }
            catch (PropertyMissingException ex)
            {
                Assert.AreEqual("ProjectPath", ex.PropertyName);
            }
            //---------------Test Result -----------------------
        }

        [Test]
        public void TestGenerate_Fails_HabaneroPathNotSet()
        {
            //---------------Set up test pack-------------------
            IProjectGenerator uiProjectGenerator = CreateProjectReadyToGenerate();
            uiProjectGenerator.SolutionGenerator.HabaneroReferencePath = null;
            //---------------Assert Precondition----------------
            Assert.IsNull(uiProjectGenerator.SolutionGenerator.HabaneroReferencePath);
            //---------------Execute Test ----------------------
            try
            {
                uiProjectGenerator.Generate();
                //---------------Test Result -----------------------
                Assert.Fail("Expected to throw an PropertyMissingException");
            }
            catch (PropertyMissingException ex)
            {
                Assert.AreEqual("SolutionGenerator.HabaneroReferencePath", ex.PropertyName);
            }
            //---------------Test Result -----------------------
        }

        [Test]
        public void TestGenerate_Fails_ModelSolutionNotSet()
        {
            //---------------Set up test pack-------------------
            IProjectGenerator uiProjectGenerator = CreateProjectReadyToGenerate();
            uiProjectGenerator.SolutionGenerator.ModelSolution = null;
            //---------------Assert Precondition----------------
            Assert.IsNull(uiProjectGenerator.SolutionGenerator.ModelSolution);
            //---------------Execute Test ----------------------
            try
            {
                uiProjectGenerator.Generate();
                //---------------Test Result -----------------------
                Assert.Fail("Expected to throw an PropertyMissingException");
            }
            catch (PropertyMissingException ex)
            {
                Assert.AreEqual("SolutionGenerator.ModelSolution", ex.PropertyName);
            }
            //---------------Test Result -----------------------
        }

        [Test]
        public void TestGenerate_Fails_ApplicationNameNotSet()
        {
            //---------------Set up test pack-------------------
            IProjectGenerator uiProjectGenerator = CreateProjectReadyToGenerate();
            uiProjectGenerator.SolutionGenerator.ModelSolution.ApplicationName = null;
            //---------------Assert Precondition----------------
            Assert.IsNull(uiProjectGenerator.SolutionGenerator.ModelSolution.ApplicationName);
            //---------------Execute Test ----------------------
            try
            {
                uiProjectGenerator.Generate();
                //---------------Test Result -----------------------
                Assert.Fail("Expected to throw an PropertyMissingException");
            }
            catch (PropertyMissingException ex)
            {
                Assert.AreEqual("SolutionGenerator.ModelSolution.ApplicationName", ex.PropertyName);
            }
            //---------------Test Result -----------------------
        }

        [Test]
        public void TestProjectPath()
        {
            //---------------Set up test pack-------------------
            string projectPath = GetRandomString();
            IProjectGenerator uiProjectGenerator = CreateProjectGenerator();
            //---------------Assert Precondition----------------
            Assert.IsNull(uiProjectGenerator.ProjectPath);
            //---------------Execute Test ----------------------
            uiProjectGenerator.ProjectPath = projectPath;
            //---------------Test Result -----------------------
            Assert.AreEqual(projectPath, uiProjectGenerator.ProjectPath);
        }

        [Test]
        public void TestHabaneroReferencePath()
        {
            //---------------Set up test pack-------------------
            string habaneroReferencePath = GetRandomString();
            IProjectGenerator uiProjectGenerator = CreateProjectGenerator();
            uiProjectGenerator.SolutionGenerator = new SolutionGenerator();
            //---------------Assert Precondition----------------
            Assert.IsNull(uiProjectGenerator.SolutionGenerator.HabaneroReferencePath);
            //---------------Execute Test ----------------------
            uiProjectGenerator.SolutionGenerator.HabaneroReferencePath = habaneroReferencePath;
            //---------------Test Result -----------------------
            Assert.AreEqual(habaneroReferencePath, uiProjectGenerator.SolutionGenerator.HabaneroReferencePath);
        }

        [Test]
        public void TestGenerate_Creates_ProjectFolder_IfDoesNotExist()
        {
            //---------------Set up test pack-------------------
            IProjectGenerator uiProjectGenerator = CreateProjectReadyToGenerate();

            //---------------Assert Precondition----------------
            Assert.IsFalse(Directory.Exists(uiProjectGenerator.ProjectPath));
            //---------------Execute Test ----------------------
            uiProjectGenerator.Generate();
            //---------------Test Result -----------------------
            Assert.IsTrue(Directory.Exists(uiProjectGenerator.ProjectPath));
        }

        [Test]
        public void TestGenerate_DoesntChange_ExistingProjectFolderOrExtraContents()
        {
            //---------------Set up test pack-------------------
            IProjectGenerator uiProjectGenerator = CreateProjectReadyToGenerate();
            Directory.CreateDirectory(uiProjectGenerator.ProjectPath);
            string tempFileName = Path.Combine(uiProjectGenerator.ProjectPath, GetRandomString());
            string tempFileContents = GetRandomString();
            File.AppendAllText(tempFileName, tempFileContents);
            //---------------Assert Precondition----------------
            Assert.IsTrue(Directory.Exists(uiProjectGenerator.ProjectPath));
            Assert.IsTrue(File.Exists(tempFileName));
            //---------------Execute Test ----------------------
            uiProjectGenerator.Generate();
            //---------------Test Result -----------------------
            Assert.IsTrue(Directory.Exists(uiProjectGenerator.ProjectPath));
            Assert.IsTrue(File.Exists(tempFileName));
            Assert.AreEqual(tempFileContents, File.ReadAllText(tempFileName));
        }

        [Test]
        public void TestGenerate_Creates_AssemblyInfo_IfDoesNotExist()
        {
            //---------------Set up test pack-------------------
            IProjectGenerator uiProjectGenerator = CreateProjectReadyToGenerate();
            string uiManagerFileName = Path.Combine(uiProjectGenerator.ProjectPath, @"Properties\AssemblyInfo.cs");
            //---------------Assert Precondition----------------
            Assert.IsFalse(File.Exists(uiManagerFileName));
            //---------------Execute Test ----------------------
            uiProjectGenerator.Generate();
            //---------------Test Result -----------------------
            Assert.IsTrue(Directory.Exists(uiProjectGenerator.ProjectPath));
            Assert.IsTrue(File.Exists(uiManagerFileName));
        }
    }
}
